package com.biz.primus.ms.stock.service;

import com.biz.primus.common.enums.StockChannelEnum;
import com.biz.primus.common.utils.CopyUtils;
import com.biz.primus.common.vo.SpringPageVO;
import com.biz.primus.model.stock.vo.IncrDepotStockReqVo;
import com.biz.primus.model.stock.vo.ProductQuantityPair;
import com.biz.primus.model.stock.vo.StockChangeLogListReqVo;
import com.biz.primus.model.stock.vo.StockChangeLogRespVo;
import com.biz.primus.ms.base.service.AbstractBaseService;
import com.biz.primus.ms.base.vo.SpringPageToSpringPageVO;
import com.biz.primus.ms.stock.dao.ChangeLogSpecification;
import com.biz.primus.ms.stock.dao.po.StockChangeLog;
import com.biz.primus.ms.stock.dao.redis.DepotStockRedisDao;
import com.biz.primus.ms.stock.dao.repository.StockChangeLogRepository;
import com.biz.primus.ms.stock.dao.ro.DepotStockRo;
import com.google.common.collect.Lists;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * StockChangeLogService
 *
 * @author JKLiues
 * @date 2017年10月23日
 */
@Service
public class StockChangeLogService extends AbstractBaseService {

    @Autowired
    private StockChangeLogRepository stockChangeLogRepository;

    @Autowired
    private DepotStockRedisDao depotStockRedisDao;

    /**
     * 库存变更记录
     *
     * @param reqVo 库存变更请求VO
     */
    public void saveLog(IncrDepotStockReqVo reqVo) {
        StockChannelEnum channelCode = reqVo.getChannelCode();
        Long version = depotStockRedisDao.getVersion(reqVo.getChannelCode());
        List<ProductQuantityPair> items = reqVo.getItems();
        List<String> productCodes = items.stream().map(ProductQuantityPair::getProductCode)
                .collect(Collectors.toList());
        String depotCode = reqVo.getDepotCode();
        List<DepotStockRo> stockRos = depotStockRedisDao.getByDepotCodesAndProductCodes(channelCode, Lists.newArrayList(depotCode), productCodes);
        Map<String, DepotStockRo> map = Optional.ofNullable(stockRos).orElse(new ArrayList<>())
                .stream()
                .collect(Collectors.toMap(DepotStockRo::getProductCode, ro -> ro));
        List<StockChangeLog> logs = items.stream().map(pair -> {
            String productCode = pair.getProductCode();
            DepotStockRo stockRo = map.getOrDefault(productCode, null);
            StockChangeLog log = new StockChangeLog(reqVo);
            log.setRemain(this.getAvailableQuantity(stockRo, version));
            log.setId(idService.getNextId());
            log.setProductCode(productCode);
            log.setQuantity(pair.getQuantity());
            return log;
        }).collect(Collectors.toList());
        stockChangeLogRepository.save(logs);
    }

    /**
     * 后台分页查询库存变更
     *
     * @param reqVo 查询请求VO
     */
    public SpringPageVO<StockChangeLogRespVo> pageResult(StockChangeLogListReqVo reqVo) {
        int page = reqVo.getPage() - 1;
        PageRequest pa = new PageRequest(page > 0 ? page : 0, reqVo.getSize());
        Page<StockChangeLog> all = stockChangeLogRepository.findAll(new ChangeLogSpecification(reqVo), pa);
        return SpringPageToSpringPageVO.of(all, po -> {
            StockChangeLogRespVo respVo = new StockChangeLogRespVo();
            CopyUtils.copyProperties(po, respVo);
            return respVo;
        });

    }

    /**
     * 获取可用库存
     *
     * @param quantity       库存数量
     * @param lockedQuantity 锁库存数量
     */
    private Integer getAvailableQuantity(Integer quantity, Integer lockedQuantity) {
        quantity = quantity == null ? 0 : quantity > 0 ? quantity : 0;
        lockedQuantity = lockedQuantity == null ? 0 : lockedQuantity > 0 ? lockedQuantity : 0;
        int i = quantity - lockedQuantity;
        return i > 0 ? i : 0;
    }

    /**
     * 获取门店可用库存
     *
     * @param stockRo 门店库存对象
     * @param version 版本号
     */
    private Integer getAvailableQuantity(DepotStockRo stockRo, Long version) {
        if (stockRo == null || version.compareTo(stockRo.getVersion()) > 0) {
            return 0;
        }
        return getAvailableQuantity(stockRo.getQuantity(), stockRo.getLockedQuantity());
    }

}